// GrabList.cpp : implementation file
//

#include "stdafx.h"
#include "manualCalib.h"
#include "GrabList.h"
#include "VideoGrab.h"
#include "cvxSf.h"
#include "CalibData.h"
#include "cvxSf.h"
#include "ExtractCorner.h"
#include "manualCalibView.h"


static string int2string(int num)
{
	char buf[256] = {NULL};
	sprintf(buf, "%d", num);
	return string(buf);
}

#define CGRABITEM_FRAME_NUMBER 0
#define CGRABITEM_TYPE         1
#define CGRABITEM_CORNER       2
#define CGRABITEM_REPROJECT_ERROR 3
#define CGRABITEM_THETA 4
#define CGRABITEM_PHI   5
#define CGRABITEM_Z_DISTANCE 6
#define CGRABITEM_ROD_ANG 7
#define CGRABITEM_N_X 8
#define CGRABITEM_N_Y 9
#define CGRABITEM_N_Z 10
#define CGRABLIST_WIDTH 60


// CGrabItem
CGrabItem::CGrabItem(IplImage *pLeft, IplImage *pRight)
{
	ASSERT(pLeft);
	ASSERT(pRight);

	m_leftImage  = cvCloneImage(pLeft);
	m_rightImage = cvCloneImage(pRight);
}

CGrabItem::~CGrabItem()
{
	if (m_leftImage)
	{
		cvReleaseImage(&m_leftImage);
	}
	if (m_rightImage)
	{
		cvReleaseImage(&m_rightImage);
	}
}

bool CGrabItem::GetCorner(bool accurate, const CvxBoard *board)
{
	if (m_leftPts.empty() && m_rightPts.empty() && board)
	{
		vector<CvxMarker> preMarkers;
		vector<CvxMarker> curMarkers;
		bool isOk = board->FindCorners(m_leftImage, false, preMarkers, curMarkers, m_leftPts);
		if (isOk)
		{
			return board->FindCorners(m_rightImage, false, preMarkers, curMarkers, m_rightPts);
		}
		else
		{
			m_leftPts.clear();
			return false;
		}
	}
	return false;
}


#define P_CHESS_BOARD 1
#define P_M_CHESS_BOARD_EXP 2
#define P_MARKER_CHESSBOARD 3
#define P_14X10  5
#define P_16X12  6
#define P_15X9   7
#define P_UL_15P2MM 9
#define P_10X6   10

// CGrabList dialog

IMPLEMENT_DYNAMIC(CGrabList, CDialog)

CGrabList::CGrabList(CWnd* pParent /*=NULL*/)
	: CDialog(CGrabList::IDD, pParent)
	, m_pParent(pParent)
	, m_rigCalib(NULL)
{

}

CGrabList::~CGrabList()
{
	POSITION aPos = m_itemList.GetHeadPosition();
	while(aPos)
	{
		CGrabItem *pItem = m_itemList.GetNext(aPos);
		if (pItem)
		{
			delete pItem, pItem = NULL;			
		}
	}
	m_itemList.RemoveAll();
}

void CGrabList::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_GRAB_LIST_LIST_CONTROL, m_controlList);
	DDX_Control(pDX, IDC_COMBO_PATTERN_TYPE, m_patternType);
	DDX_Control(pDX, IDC_COMBO_PATTERN_SIZE, m_patternSize);
	DDX_Control(pDX, IDC_COMBO_UNIT_LENGTH, m_unitLength);
}


BEGIN_MESSAGE_MAP(CGrabList, CDialog)
	ON_BN_CLICKED(IDOK, &CGrabList::OnBnClickedOk)
	ON_BN_CLICKED(IDCANCEL, &CGrabList::OnBnClickedCancel)
	ON_BN_CLICKED(IDC_GRAB_LIST_RIG_CALIBRATION, &CGrabList::OnBnClickedGrabListRigCalibration)
//	ON_NOTIFY(LVN_ITEMCHANGED, IDC_GRAB_LIST_LIST_CONTROL, &CGrabList::OnLvnItemchangedGrabListListControl)
	ON_NOTIFY(NM_DBLCLK, IDC_GRAB_LIST_LIST_CONTROL, &CGrabList::OnNMDblclkGrabListListControl)
	ON_BN_CLICKED(IDC_GRABLIST_SAVE_IMG, &CGrabList::OnBnClickedGrablistSaveImg)
	ON_BN_CLICKED(IDC_GRABLIST_LOADIMG, &CGrabList::OnBnClickedGrablistLoadimg)
	ON_NOTIFY(NM_RCLICK, IDC_GRAB_LIST_LIST_CONTROL, &CGrabList::OnNMRClickGrabListListControl)
	ON_COMMAND(ID_GRIDITEMPOPUP_DELETE, &CGrabList::OnGriditempopupDelete)
	ON_BN_CLICKED(IDC_ADD_IMAGES, &CGrabList::OnBnClickedAddImages)
	ON_CBN_SELCHANGE(IDC_COMBO_PATTERN_TYPE, &CGrabList::OnCbnSelchangeComboPatternType)
	ON_BN_CLICKED(IDC_BUTTON_SET_PATTERN, &CGrabList::OnBnClickedButtonSetPattern)
	ON_BN_CLICKED(IDC_GRABLIST_SAVE_PTS, &CGrabList::OnBnClickedGrablistSavePts)
END_MESSAGE_MAP()


// CGrabList message handlers

void CGrabList::OnBnClickedOk()
{
	// TODO: Add your control notification handler code here
	if (UpdateData(true))
	{
		m_pParent->UpdateData(false);
		DestroyWindow();
	}
	//OnOK();
}

void CGrabList::OnBnClickedCancel()
{
	// TODO: Add your control notification handler code here
	DestroyWindow();
	//OnCancel();
}

void CGrabList::PostNcDestroy()
{
	// TODO: Add your specialized code here and/or call the base class

	CDialog::PostNcDestroy();

	if(m_pParent)
	{
		if (typeid(*m_pParent) == typeid(CVideoGrab))
		{
			((CVideoGrab*)m_pParent)->m_grabList = NULL;
		}
		else if (typeid(*m_pParent) == typeid(CmanualCalibView))
		{
			((CmanualCalibView*)m_pParent)->m_grabList = NULL;
		}
		
	}
	delete this;
}

// add image pair to grab list
void CGrabList::AddList(int framNum, IplImage * left, IplImage * right)
{
	ASSERT(left);
	ASSERT(right);

	//add to date item
	CGrabItem *pItem = new CGrabItem(left, right);
	bool isCorner = pItem->GetCorner(false, m_board);

	m_itemList.AddTail(pItem);

	string sFrame = int2string(framNum);
	//add to view item
	LVITEM lvItem;
	int nItem;

	//left
	lvItem.mask = LVIF_TEXT;
	lvItem.iItem = m_controlList.GetItemCount();
	lvItem.iSubItem = 0;
	lvItem.pszText = const_cast<char *>(sFrame.c_str());
	nItem = m_controlList.InsertItem(&lvItem);
	m_controlList.SetItemText(nItem, 1, "Left");
	if (isCorner)
	{
		m_controlList.SetItemText(nItem, 2, "Yes");
	}
	else
	{
		m_controlList.SetItemText(nItem, 2, "No");
	}
// 	m_controlList.SetItemText(nItem, 3, "N/A");
// 	m_controlList.SetItemText(nItem, CGRABITEM_THETA, "N/A");
// 	m_controlList.SetItemText(nItem, CGRABITEM_PHI, "N/A");
// 	m_controlList.SetItemText(nItem, CGRABITEM_Z_DISTANCE, "N/A");
	

	//right
	lvItem.mask = LVIF_TEXT;
	lvItem.iItem = m_controlList.GetItemCount();
	lvItem.iSubItem = 0;
	nItem = m_controlList.InsertItem(&lvItem);
	m_controlList.SetItemText(nItem, 1, "right");
	if (isCorner)
	{
		m_controlList.SetItemText(nItem, 2, "Yes");
	}
	else
	{
		m_controlList.SetItemText(nItem, 2, "No");
	}
// 	m_controlList.SetItemText(nItem, 3, "N/A");
// 	m_controlList.SetItemText(nItem, CGRABITEM_THETA, "N/A");
// 	m_controlList.SetItemText(nItem, CGRABITEM_PHI, "N/A");
// 	m_controlList.SetItemText(nItem, CGRABITEM_Z_DISTANCE, "N/A");
}

void CGrabList::updateReprojectionError(const vector<float> &left, const vector<float> &right)
{
	//only left, left is all yes
	if (right.size() == 0 && left.size() * 2 == m_controlList.GetItemCount())
	{
		for (int i = 0; i<left.size(); ++i)
		{
			char bufA[255] = {NULL};
			sprintf(bufA, "%.2f", left[i]);
			m_controlList.SetItemText(2*i,  3, bufA);
		}
	}
	//only left, left partly yes
	else if (right.size() == 0 && left.size() * 2 < m_controlList.GetItemCount())
	{
		int aCount =  m_controlList.GetItemCount(); 
		if (aCount > 0)
		{			
			for (int nItem = 0, i = 0; nItem<aCount && i<left.size(); nItem = nItem + 2)
			{
				CString aStr = m_controlList.GetItemText(nItem, 2);
				if (aStr == CString("Yes"))
				{
					char bufA[255] = {NULL};
					sprintf(bufA, "%.2f", left[i]);
					m_controlList.SetItemText(nItem,  3, bufA);
					i++;
				}			
			}
		}

	}
	else if(left.size() + right.size() == m_controlList.GetItemCount())
	{
		for (int i = 0; i<left.size() && i<right.size(); ++i)
		{
			char bufA[255] = {NULL};
			char bufB[255] = {NULL};
			sprintf(bufA, "%.2f", left[i]);
			sprintf(bufB, "%.2f", right[i]);
			m_controlList.SetItemText(2*i,  3, bufA);
			m_controlList.SetItemText(2*i+1, 3, bufB);
		}
	}
	else
	{
		//some item has no corner
		int aCount =  m_controlList.GetItemCount(); 
		if (aCount > 0)
		{			
			for (int nItem = 0, i = 0; nItem<aCount && i<left.size() && i<right.size(); nItem = nItem + 2)
			{
				CString aStr = m_controlList.GetItemText(nItem, 2);
				if (aStr == CString("Yes"))
				{
					char bufA[255] = {NULL};
					char bufB[255] = {NULL};
					sprintf(bufA, "%.2f", left[i]);
					sprintf(bufB, "%.2f", right[i]);
					m_controlList.SetItemText(nItem,  3, bufA);
					m_controlList.SetItemText(nItem+1, 3, bufB);					
					i++;
				}			
			}
		}

	}
}

void CGrabList::updateOrientation(const vector<float> &theta, const vector<float> &phi, 
								  const vector<float> &z_dis, const vector<float> &rod,
								  const vector<Vec3d> &normalVec,
								  bool isLeft)
{
	assert(theta.size() == phi.size() && phi.size() == z_dis.size());
	assert(theta.size() > 0);

	if (isLeft)
	{
		int aCount =  m_controlList.GetItemCount(); 
		for (int nItem = 0, i = 0; nItem<aCount && i<theta.size(); nItem = nItem + 2)
		{
			CString aStr = m_controlList.GetItemText(nItem, 2);
			if (aStr == CString("Yes"))
			{
				char bufTheta[255] = {NULL};
				char bufPhi[255]  = {NULL};
				char bufZdis[255] = {NULL};
				char bufRod[255]  = {NULL};
				char bufNormalX[255]  = {NULL};
				char bufNormalY[255]  = {NULL};
				char bufNormalZ[255]  = {NULL};
				sprintf(bufTheta, "%.2f", theta[i]);
				sprintf(bufPhi, "%.2f", phi[i]);
				sprintf(bufZdis, "%.2f", z_dis[i]);
				sprintf(bufRod, "%.2f", rod[i]);
				sprintf(bufNormalX, "%.2f", normalVec[i][0]);
				sprintf(bufNormalY, "%.2f", normalVec[i][1]);
				sprintf(bufNormalZ, "%.2f", normalVec[i][2]);
				m_controlList.SetItemText(nItem, CGRABITEM_THETA, bufTheta);
				m_controlList.SetItemText(nItem, CGRABITEM_PHI, bufPhi);	
				m_controlList.SetItemText(nItem, CGRABITEM_Z_DISTANCE, bufZdis);
				m_controlList.SetItemText(nItem, CGRABITEM_ROD_ANG, bufRod);
				m_controlList.SetItemText(nItem, CGRABITEM_N_X, bufNormalX);
				m_controlList.SetItemText(nItem, CGRABITEM_N_Y, bufNormalY);
				m_controlList.SetItemText(nItem, CGRABITEM_N_Z, bufNormalZ);
				++i;
			}			
		}
	}

}



BOOL CGrabList::OnInitDialog()
{
	CDialog::OnInitDialog();

	// TODO:  Add extra initialization here

	LVCOLUMN lvColumn;

	m_controlList.SetExtendedStyle(m_controlList.GetExtendedStyle()|
							LVS_EX_FULLROWSELECT |LVS_EX_GRIDLINES);

	//m_controlList.SetExtendedStyle(m_controlList.GetExtendedStyle()|   
	//	LVS_EX_FULLROWSELECT| LVS_EX_GRIDLINES | LVS_EX_TRACKSELECT);


	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH - 20;
	lvColumn.pszText = "Idx";
	m_controlList.InsertColumn(CGRABITEM_FRAME_NUMBER, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Type";
	m_controlList.InsertColumn(CGRABITEM_TYPE, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Corner";
	m_controlList.InsertColumn(CGRABITEM_CORNER, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Repro Err";
	m_controlList.InsertColumn(CGRABITEM_REPROJECT_ERROR, &lvColumn);

	//show extrinsic parameters
	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Theta";
	m_controlList.InsertColumn(CGRABITEM_THETA, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Phi";
	m_controlList.InsertColumn(CGRABITEM_PHI, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Z Dis";
	m_controlList.InsertColumn(CGRABITEM_Z_DISTANCE, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Rodrigues";
	m_controlList.InsertColumn(CGRABITEM_ROD_ANG, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Normal x";
	m_controlList.InsertColumn(CGRABITEM_N_X, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Normal y";
	m_controlList.InsertColumn(CGRABITEM_N_Y, &lvColumn);

	lvColumn.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
	lvColumn.fmt = LVCFMT_LEFT;
	lvColumn.cx = CGRABLIST_WIDTH;
	lvColumn.pszText = "Normal z";
	m_controlList.InsertColumn(CGRABITEM_N_Z, &lvColumn);

	

	//set board parameters
	m_patternType.SetItemData(m_patternType.AddString("Chessboard"), P_CHESS_BOARD);
	m_patternType.SetItemData(m_patternType.AddString("Marker Chessboard"), P_MARKER_CHESSBOARD);
	m_patternType.SetItemData(m_patternType.AddString("Marker Chessboard Exp"), P_M_CHESS_BOARD_EXP);
	m_patternType.SetCurSel(1);

	m_patternSize.SetItemData(m_patternSize.AddString("0: 14 X 10"), P_14X10);
	m_patternSize.SetItemData(m_patternSize.AddString("1: 16 X 12"), P_16X12);
	m_patternSize.SetItemData(m_patternSize.AddString("2: 15 X 9"), P_15X9);
	m_patternSize.SetItemData(m_patternSize.AddString("3: 10 X 6"), P_10X6);
	m_patternSize.SetCurSel(0);

	m_unitLength.SetItemData(m_unitLength.AddString("1: 15.2mm"), P_UL_15P2MM);	
	m_unitLength.SetCurSel(0);

	//set default checker board
	m_board = new CvxMarkerChessboard;
	assert(m_board);
	m_board->SetConfigure(cvSize(14, 10), 15.2);


	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

void CGrabList::OnBnClickedGrabListRigCalibration()
{
	// TODO: Add your control notification handler code here
	if (m_rigCalib)
	{
		m_rigCalib->ShowWindow(SW_SHOW);
		m_rigCalib->SetForegroundWindow();
	}
	else
	{
		m_rigCalib = new CRigCalib(this);
		m_rigCalib->Create(CRigCalib::IDD, this);
		m_rigCalib->ShowWindow(SW_SHOW);
	}	
}



void CGrabList::OnNMDblclkGrabListListControl(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;

	int nItem  =  m_controlList.GetSelectionMark();
	if(nItem == -1) 
	{
		return;
	}
	int numItem = nItem/2 + 1;
	CGrabItem* pItem = NULL;
	POSITION aPos = m_itemList.GetHeadPosition();
	while(numItem--)
	{
		pItem = m_itemList.GetNext(aPos);			
	}
	if (pItem == NULL)
	{
		return;
	}

	// get corresponding image and corner points
	CString aStr = m_controlList.GetItemText(nItem, 2);
	IplImage *pImage = NULL;
	vector<Point2f> *pPts = NULL;
//	vector<Point3f> *pPts3d = NULL;
	if (nItem%2 == 0)
	{
		pImage = pItem->m_leftImage;
		pPts = &(pItem->m_leftPts);	
//		pPts3d = &(pItem->m_leftPts3D);
	}
	else
	{
		pImage = pItem->m_rightImage;
		pPts = &(pItem->m_rightPts);
//		pPts3d = &(pItem->m_rightPts3D);
	}

	//when corners have been detected, just show the result
	if (aStr == CString("Yes"))
	{
		IplImage *tImage = cvCloneImage(pImage);
		if (m_board)
		{
			m_board->DrawCorners(tImage, *pPts);
		}
		
		CExtractCorner extDlg;
		extDlg.addImage(tImage, m_board);
 		if(extDlg.DoModal() == IDOK)
 		{
 
 		}
		cvReleaseImage(&tImage);
	}
	else
	{
		// when corner is not automatically detected.
		CExtractCorner extDlg;
		
		extDlg.addImage(pImage, m_board);		
		extDlg.setPts(pPts);
		if(extDlg.DoModal() == IDOK)
		{
			m_controlList.SetItemText(nItem, 2, "Yes");
		}
		else
		{
			pPts->clear();
	//		pPts3d->clear();
		}		
		
	}
	
}


void CGrabList::OnBnClickedGrablistSaveImg()
{
	// TODO: Add your control notification handler code here
	// save files to a folder
	//@todo
	vector<IplImage*> imageLeft;
	vector<IplImage*> imageRight;
	POSITION aPos = m_itemList.GetHeadPosition();
	while(aPos)
	{
 		CGrabItem *item = m_itemList.GetNext(aPos);
 		imageLeft.push_back(item->m_leftImage);
 		imageRight.push_back(item->m_rightImage);
 	}
    CvxSF::saveImageVec(imageLeft, string("left"), string(".png"), "");
 	CvxSF::saveImageVec(imageRight, string("right"), string(".png"), "");
}

void CGrabList::OnBnClickedGrablistLoadimg()
{
	// TODO: Add your control notification handler code here

	//load left and right image names
	AfxMessageBox(_T("Load left images!"), MB_OK);

	CList<CString, CString&> leftNameList;
	CList<CString, CString&> rightNameList;

	//record left name
	{
		CFileDialog dlgLeftFile(TRUE);
		CString fileName;
		const int c_cMaxFiles = 100;
		const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
		dlgLeftFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
		dlgLeftFile.GetOFN().nMaxFile = c_cbBuffSize;
		dlgLeftFile.GetOFN().Flags = dlgLeftFile.GetOFN().Flags | OFN_ALLOWMULTISELECT ;	

		if (dlgLeftFile.DoModal() == IDOK)
		{
			POSITION pos = dlgLeftFile.GetStartPosition();
			while(pos)
			{
				leftNameList.AddTail(dlgLeftFile.GetNextPathName(pos));
			}
		}
		fileName.ReleaseBuffer();
	}

	//record right files
	{
		CFileDialog dlgRightFile(TRUE);
		CString fileName;
		const int c_cMaxFiles = 100;
		const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
		dlgRightFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
		dlgRightFile.GetOFN().nMaxFile = c_cbBuffSize;
		dlgRightFile.GetOFN().Flags = dlgRightFile.GetOFN().Flags | OFN_ALLOWMULTISELECT ;	

		if (dlgRightFile.DoModal() == IDOK)
		{
			POSITION pos = dlgRightFile.GetStartPosition();
			while(pos)
			{
				rightNameList.AddTail(dlgRightFile.GetNextPathName(pos));
			}
		}
		fileName.ReleaseBuffer();
	}
	if (leftNameList.GetCount() != rightNameList.GetCount())
	{
		AfxMessageBox(_T("left Image number != right image number, failed!"), MB_OK);
		return;
	}

	//clean m_controlList m_itemList
	POSITION aPos = m_itemList.GetHeadPosition();
	while(aPos)
	{
		CGrabItem *pItem = m_itemList.GetNext(aPos);
		if (pItem)
		{
			delete pItem, pItem = NULL;			
		}
	}
	m_itemList.RemoveAll();
	m_controlList.DeleteAllItems();

	//load image and extract corner

 	POSITION lPos = leftNameList.GetHeadPosition();
	POSITION rPos = rightNameList.GetHeadPosition();
	int frameNum = 0;
 	while (lPos && rPos)
 	{
 		const char *leftName = leftNameList.GetNext(lPos).GetBuffer(0);
		const char *rightName = rightNameList.GetNext(rPos).GetBuffer(0);
		IplImage *leftImage = cvLoadImage(leftName, 1);
		IplImage *rightImage = cvLoadImage(rightName, 1);
		if (leftImage && rightImage)
		{
			AddList(frameNum++, leftImage, rightImage);
			cvReleaseImage(&leftImage);
			cvReleaseImage(&rightImage);
		}
		else
		{
			AfxMessageBox(_T("can not load image, failed!"), MB_OK);
			return;
		}
 	}	

}

void CGrabList::OnNMRClickGrabListListControl(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: Add your control notification handler code here

	// add context menu here
	CMenu menu;
	menu.LoadMenu(IDR_MENU_GRIB_ITEM_CONTEXT);
	CPoint point;   
	::GetCursorPos(&point); 

	CMenu *pPopup = menu.GetSubMenu(0);
	ASSERT(pPopup != NULL);
	pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,  point.x, point.y, this);

	//add end
	*pResult = 0;
}

void CGrabList::OnGriditempopupDelete()
{
	// TODO: Add your command handler code here

	// delete current item in the m_controlList and m_itemList
	int nItem  =  m_controlList.GetSelectionMark();
	if(nItem == -1) 
	{
		return;
	}
	int numItem = nItem/2 + 1;
	CGrabItem* pItem = NULL;
	POSITION aPos = m_itemList.GetHeadPosition();
	POSITION prePos = aPos;
	while(numItem--)
	{
		prePos = aPos;
		pItem = m_itemList.GetNext(aPos);			
	}
	if (pItem == NULL)
	{
		return;
	}
	
	//delete CGrabItem
	m_itemList.RemoveAt(prePos);
	delete pItem;
	pItem = NULL;
	//delete m_controlList
	if (nItem %2 == 0) //left image
	{
		m_controlList.DeleteItem(nItem);
		m_controlList.DeleteItem(nItem);

	}
	else               //right image
	{
		assert(nItem - 1>= 0);
		m_controlList.DeleteItem(nItem - 1);
		m_controlList.DeleteItem(nItem - 1);
	}
}

void CGrabList::OnBnClickedAddImages()
{
	// TODO: Add your control notification handler code here

	// add image to grab list
	//load left and right image names
	AfxMessageBox(_T("Add left images!"), MB_OK);

	CList<CString, CString&> leftNameList;
	CList<CString, CString&> rightNameList;

	//record left name
	{
		CFileDialog dlgLeftFile(TRUE);
		CString fileName;
		const int c_cMaxFiles = 50;
		const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
		dlgLeftFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
		dlgLeftFile.GetOFN().nMaxFile = c_cbBuffSize;
		dlgLeftFile.GetOFN().Flags = dlgLeftFile.GetOFN().Flags | OFN_ALLOWMULTISELECT ;	

		if (dlgLeftFile.DoModal() == IDOK)
		{
			POSITION pos = dlgLeftFile.GetStartPosition();
			while(pos)
			{
				leftNameList.AddTail(dlgLeftFile.GetNextPathName(pos));
			}
		}
		fileName.ReleaseBuffer();
	}

	//record right files
	{
		CFileDialog dlgRightFile(TRUE);
		CString fileName;
		const int c_cMaxFiles = 50;
		const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
		dlgRightFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
		dlgRightFile.GetOFN().nMaxFile = c_cbBuffSize;
		dlgRightFile.GetOFN().Flags = dlgRightFile.GetOFN().Flags | OFN_ALLOWMULTISELECT ;	

		if (dlgRightFile.DoModal() == IDOK)
		{
			POSITION pos = dlgRightFile.GetStartPosition();
			while(pos)
			{
				rightNameList.AddTail(dlgRightFile.GetNextPathName(pos));
			}
		}
		fileName.ReleaseBuffer();
	}
	if (leftNameList.GetCount() != rightNameList.GetCount())
	{
		AfxMessageBox(_T("left Image number != right image number, failed!"), MB_OK);
		return;
	}


	//load image and extract corner

	POSITION lPos = leftNameList.GetHeadPosition();
	POSITION rPos = rightNameList.GetHeadPosition();
	int frameNum = m_controlList.GetItemCount()/2;
	while (lPos && rPos)
	{
		const char *leftName = leftNameList.GetNext(lPos).GetBuffer(0);
		const char *rightName = rightNameList.GetNext(rPos).GetBuffer(0);
		IplImage *leftImage = cvLoadImage(leftName, 1);
		IplImage *rightImage = cvLoadImage(rightName, 1);
		if (leftImage && rightImage)
		{
			AddList(frameNum++, leftImage, rightImage);
			cvReleaseImage(&leftImage);
			cvReleaseImage(&rightImage);
		}
		else
		{
			AfxMessageBox(_T("can not load image, failed!"), MB_OK);
			return;
		}
	}	

}

void CGrabList::OnCbnSelchangeComboPatternType()
{
	// TODO: Add your control notification handler code here
	int curV = (int)m_patternType.GetItemData(m_patternType.GetCurSel());
	if (curV == P_CHESS_BOARD)
	{
		m_patternSize.SetCurSel(0);
		m_unitLength.SetCurSel(0);
	}
	else if (curV == P_MARKER_CHESSBOARD)
	{
		m_patternSize.SetCurSel(1);
		m_unitLength.SetCurSel(1);
	}
	else if (curV == P_M_CHESS_BOARD_EXP)
	{
		m_patternSize.SetCurSel(2);
		m_unitLength.SetCurSel(2);
	}
}

void CGrabList::OnBnClickedButtonSetPattern()
{
	// TODO: Add your control notification handler code here
	if (m_board)
	{
		delete m_board;
		m_board = NULL;
	}
	CvSize size;
	float unitLength;

	int val = (int)m_patternSize.GetItemData(m_patternSize.GetCurSel());
	if (val == P_14X10)
	{
		size = cvSize(14, 10);
	}
	else if (val == P_16X12)
	{
		size = cvSize(16, 12);
	}
	else if (val == P_15X9)
	{
		size = cvSize(15, 9);
	}
	else if(val == P_10X6)
	{
		size = cvSize(10, 6);
	}
	else
	{
		AfxMessageBox(_T("undefined value!"), MB_OK);
		return;
	}	

	val = (int)m_unitLength.GetItemData(m_unitLength.GetCurSel());
	if (val == P_UL_15P2MM)
	{
		unitLength = 15.2;  //small marker chessboard
	}	
	else
	{
		AfxMessageBox(_T("undefined value!"), MB_OK);
		return;
	}

	int curV = (int)m_patternType.GetItemData(m_patternType.GetCurSel());
	if (curV == P_CHESS_BOARD)
	{
		m_board = new CvxChessboard;
		assert(m_board);
		m_board->SetConfigure(size, unitLength);
		
	}
	else if (curV == P_M_CHESS_BOARD_EXP)
	{
		m_board = new CvxMarkerChessboardExp;
		assert(m_board);
		m_board->SetConfigure(size, unitLength);
	}
	else if (curV == P_MARKER_CHESSBOARD)
	{
		m_board = new CvxMarkerChessboard;
		assert(m_board);
		m_board->SetConfigure(size, unitLength);
	}
	
}

void CGrabList::OnBnClickedGrablistSavePts()
{
	// TODO: Add your control notification handler code here
	string saveFile;
	CFileDialog dlgFile(FALSE, "txt", "_left_pts.txt", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "TXT (*.txt)", NULL);
	if (dlgFile.DoModal() == IDOK)
	{
		saveFile = dlgFile.GetPathName();		
	}
	if (!saveFile.empty())
	{
		if (m_board)
		{
			CvSize size = m_board->GetPatternSize();
			vector<vector<Point2f>> ptsVec;
			POSITION aPos = m_itemList.GetHeadPosition();
			while(aPos)
			{
				CGrabItem *pItem = m_itemList.GetNext(aPos);
				if (pItem)
				{
					ptsVec.push_back(pItem->m_leftPts);		
				}
			}
			CvxSF::saveChessboard(string("No video file"), saveFile, ptsVec, size);
			AfxMessageBox(_T("left pts saved!"), MB_OK);
			return;
		}
	}
	AfxMessageBox(_T("save left pts failed!"), MB_OK);
}
